package com.caimiao.miao.library.usb.logic;

import com.caimiao.miao.http.rxjava.transformer.SchedulerTransformer;
import com.caimiao.miao.library.usb.interfaces.IUsbControl;
import com.caimiao.miao.library.usb.interfaces.IUsbScheduler;
import com.caimiao.miao.library.usb.accessory.Command;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;

/**
 * USB数据调度器
 */
public class UsbScheduler implements IUsbScheduler {
    private static final String TAG = "UsbScheduler";
    private Disposable mDisposable;
    private volatile boolean isReadFlag;
    private IUsbControl mUsbControl;

    private final int retryLimit = 5;//重试次数
    private final long readTimeout = 50;//读取超时
    private final long intervalTime = 500;//发送连接命令的间隔
    private long mCurTime;
    private long mLastTime;
    private int mRetryCount;
    private long mReadTime;
    private long mTotalTime;

    protected static char[] sendLastData = null;


    public UsbScheduler(IUsbControl mUsbInterface) {
        this.mUsbControl = mUsbInterface;
        start();
    }

    @Override
    public void close() {
        if (mDisposable != null)
            mDisposable.dispose();
        mDisposable = null;
    }

    @Override
    public void start() {
        reset();
        mDisposable = Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
                .map(new Function<Long, Command>() {
                    @Override
                    public Command apply(Long aLong) throws Exception {
                        Command command;
                        if (isReadFlag) {//read
                            command = Command.Util.checkReadData(mUsbControl.getReadData());
                            if (command == null)
                                command = new Command(UsbCode.SCHEDULER_STATUS_READ, null);
                        } else {//write
                            command = mUsbControl.nextCommand();
                            if (command == null)
                                command = new Command(UsbCode.SCHEDULER_STATUS_WRITE, null);
                        }
                        return command;
                    }
                })
                .map(new Function<Command, Command>() {
                    @Override
                    public Command apply(Command command) throws Exception {
                        //间隔执行时间
                        final long interval = getIntervalTime();
                        mTotalTime += interval;
                        command.setInterval(interval);
                        return command;
                    }
                })
                .doOnNext(new Consumer<Command>() {
                    @Override
                    public void accept(Command command) throws Exception {
                        if (!isReadFlag) {//write mode
                            if (command.getCommand() != null) {
                                isReadFlag = true;
                                mUsbControl.sendData(command.getCommand());
                                sendLastData = command.getCommand();//备份，重发有用
                                mUsbControl.clearReadData();
                            }
                            mReadTime = 0;//重置读取超时
                            mRetryCount = 0;//重置读取次数
                        } else {//call mode
                            if (command.getCommand() != null) {//读取成功
                                isReadFlag = false;
                                //后续处理交给主线程
                            } else {//读取失败
                                mReadTime += command.getInterval();
                                if (mReadTime > readTimeout) {//读取超时
                                    if (mRetryCount < retryLimit) {
                                        //重发(出票重发需注意设备可能已经在出票了)
//                                        mUsbControl.sendData(sendLastData);
//                                        mUsbControl.clearReadBufferData();
                                        mReadTime = 0;
                                        mRetryCount++;
                                    } else {//超出次数
                                        command.setStatus(UsbCode.SCHEDULER_STATUS_TIMEOUT);
                                        command.setCommand(mUsbControl.getReadData());
                                    }
                                }
                            }
                        }
                        if (mTotalTime > intervalTime) {
                            mTotalTime = 0;
                            prepareFor100MS();
                        }
                    }
                })
                .compose(SchedulerTransformer.applyIoAndUi())
                .subscribe(new Consumer<Command>() {
                    @Override
                    public void accept(Command command) throws Exception {
                        mUsbControl.callback(command);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                    }
                });
    }


    private void reset() {
        mLastTime = mCurTime = System.currentTimeMillis();
        mTotalTime = 0;
        mReadTime = 0;
        mRetryCount = 0;
    }

    ///获取两次执行的间隔时间
    private long getIntervalTime() {
        mCurTime = System.currentTimeMillis();
        long interval = mCurTime - mLastTime;
        mLastTime = mCurTime;
        return interval;
    }

    //没100mS获取一次感应情况和连接情况
    private void prepareFor100MS() {
        mUsbControl.addLastCmdToWriteQueue(Command.Util.getCommand(UsbCode.GET_INDUCTION_STATUS, 0, 0));
        mUsbControl.addLastCmdToWriteQueue(Command.Util.getCommand(UsbCode.GET_CONNECT_STATUS, 0, 0));
    }
}
